package com.manage.cloud.config;

import com.manage.cloud.customize.CustomAccessDeniedHandler;
import com.manage.cloud.customize.AuthExceptionEntryPoint;
import com.manage.cloud.properties.ExcludeTokenProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;

import javax.annotation.Resource;

/**
 * @author zhangqing
 */
@Slf4j
@Configuration
@EnableResourceServer
@RequiredArgsConstructor
@EnableConfigurationProperties(ExcludeTokenProperties.class)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private final AuthExceptionEntryPoint authExceptionEntryPoint;
    private final CustomAccessDeniedHandler customAccessDeniedHandler;
    private final ExcludeTokenProperties excludeTokenProperties;

    @Resource
    private OAuth2WebSecurityExpressionHandler expressionHandler;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        log.error(excludeTokenProperties.getExclude().toString());
        http.csrf().disable()
                .authorizeRequests().antMatchers(excludeTokenProperties.getExclude().getTokenFilterExclude()).permitAll()
                .and()
                .authorizeRequests()
                .anyRequest().authenticated();//其他所有接口走自定义权限判断;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        remoteTokenServices.setClientId("system-web");
        remoteTokenServices.setClientSecret("123456");
        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:9091/oauth/check_token");
        //认证服务器配置的资源id
        resources
                //自定义权限校验异常
                .accessDeniedHandler(customAccessDeniedHandler)
                //自定义token校验异常
                .authenticationEntryPoint(authExceptionEntryPoint)
                .tokenServices(remoteTokenServices);
    }

    @Bean
    public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler(ApplicationContext applicationContext) {
        OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
        expressionHandler.setApplicationContext(applicationContext);
        return expressionHandler;
    }

    /**
     * 自定义JWT Converter
     *
     * @return
     * @see JwtAuthenticationProvider#setJwtAuthenticationConverter(Converter)
     */
    public Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }

}
